/****************************************Copyright (c)**********************************************
**                               		特飞科技公司
**
* 文    件 : 串口驱动头文件
* 作    者 : 李海洋
* 版    本 ：v1.0
* 完成时间 : 2023年6月24日
* 描    述 ：***串口驱动特色***
* 1.支持有操作系统的和无操作系统的使用,能自动识别,无需事先配置有无使用操作系统.
* 2.串口驱动中接收驱动采用是空闲中断法断帧.
* 3.支持新旧HAL驱动库.旧HAL驱动版本不支持空闲中断,因此驱动同时存在空闲中断补丁和使用HAL中的空闲中断驱动,根据实际应用进行配置.
* 4.使用HAL中的空闲中断驱动支持DMA使用循环模式和普通模式,但本驱动只支持循环模式;因补丁空闲中断驱动只支持DMA使用循环模式.
* 5.支持1帧中出现2次以上"打嗝"式空闲中断,断帧的空闲时间间隔长短由用户指定.
* ***串口驱动使用方法:***
* 1.1.将头文件UartDriver.h中的配置项拷贝到系统配置文件SysConfig.h中(如果有)或Includes.h中靠前位置,并进行配置.
* 根据实际使用串口数量配置串口使用个数 USE_UART_NUM
* 串口驱动中接收驱动采用是空闲中断法断帧,之前HAL驱动版本不支持空闲中断,所以默认是使用空闲中断补丁,如果使用最新版本HAL
* 则可以使能使用HAL中的空闲中断驱动,即:
	#define UART_USE_HAL_IDLE_INT		//定义是否使用HAL中的空闲中断驱动
* 两者区别:补丁效率要高些,但兼容性及方便程度不如HAL库驱动
* 1.2.将头文件UartDriver.h包含在Includes.h中.
* 1.3.申请2个接收缓冲区: 1个RxBuf用于给DMA做循环缓冲,长度要求大于接收最大帧长;另一个FrBuf用于顺序存放接收的帧数据,长度要求大于接收最大帧长. 如:
	#define RX_BUF_SIZE		200
	uint8_t RxBuf[RX_BUF_SIZE];
	uint8_t FrBuf[RX_BUF_SIZE];
* 1.4.申请一个指向串口驱动对象的指针: UartDriver * UartObj;
* 1.5.注册串口对象,调用:
	int UD_Register(
	UartDriver **obj,	//[IO]指向驱动对象
	UART_HandleTypeDef *huart,//[I]指向Uart句柄
	unsigned char *rxBuf,//[I]接收缓冲区
	unsigned char *frBuf,//[I]帧数据缓冲区
	unsigned int bufSize);//[I]缓冲区大小
* 1.6.对注册过的串口对象成员变量初始化,调用:
	void UD_Init(
	UartDriver *obj,//[I]注册过的串口对象
	Sem_Def	txSem,//[I]发送信号量,等待Uart发送完成否? NULL|-1:不等, 其它:等.
	Sem_Def	rxSem,//[I]接收信号量
	int readTimeout,//[I]读取数据超时时间ms: osWaitForever|很大数:直到收到数据, 其它:在给定时间内没收到数据.
	int idleInterval);//[I]判断空闲时间间隔ms
* idleInterval设定很重要,影响接收性能!要根据应用环境和设备性能做全面测试.
	太小->有些"打嗝"时间长的帧将会出现误判!
	太大->可能与下一帧数据重叠,影响驱动器性能!
	一般选择2-5ms较好!
* 1.7.发送: 调用以下方法启动发送数据即可:
	int UD_Transmit(
	UartDriver * obj,//[I]注册并初始化过的串口对象
	unsigned char *pTxBuf,//[I]指向发送数据存放位置 
	unsigned int size);//[I]传输字节数
* 1.8.重写:读取1帧数据发生超时回调函数
	void UD_ReadTimeoutCallBack(UartDriver *obj) //[I]注册过的串口对象
* 如果在方法UD_Init中设定了readTimeout读取数据超时时间ms,则应重写超时回调函数对发生超时事件应该做些什么事情在其中编写完成.
* 当有多个串口分布在不同文件中时推荐使用如下模板:
	//描述: 处理无线超时
	//返回: true:是无线超时并已处理; false:不是无线超时
	bool RF_ProcessingTimeout(UartDriver *obj) //[I]注册过的串口对象
	{
		if (obj != RF_Obj)
			return false;
		...
		return true;
	}
	//描述: 处理惯导超时
	//返回: true:是惯导超时并已处理; false:不是惯导超时
	bool INS_ProcessingTimeout(UartDriver *obj); //[I]注册过的串口对象
	//描述: 处理GPS超时
	//返回: true:是GPS超时并已处理; false:不是GPS超时
	bool GPS_ProcessingTimeout(UartDriver *obj); //[I]注册过的串口对象
	//重写:读取1帧数据发生超时回调函数
	void UD_ReadTimeoutCallBack(UartDriver *obj) //[I]注册过的串口对象
	{
		if (RF_ProcessingTimeout(obj) == true)
			return;
		if (INS_ProcessingTimeout(obj) == true)
			return;
		if (GPS_ProcessingTimeout(obj) == true)
			return;
	}
* 1.9.重写:通知调用者"我还活着"--运行正常
	void UD_NoticeAliveCallBack(UartDriver *obj); //[I]注册过的串口对象
* 如果不关心读取1帧串口数据是否"卡死"可以不重写;	如果关心并且1帧数据传输时间大于监视周期则可在此回调函数中清零计时器.
* 1.10.接收: 如果确定每帧只有1个空闲中断出现,则等中断,中断到后对接收的帧数据进行解码.(不推荐用这种方式)
* 或者调用:
	int UD_ReadFrameData(UartDriver *obj);//[I]注册并初始化过的串口对象
* 在FrBuf中获得1帧完整数据和帧长度:由IdleInterval(空闲间隔时间)给定断帧的数据包,然后对接收的帧数据进行解码.
**--------------------------------------------------------------------------------------------------
* 修 改 人 ：
* 版    本 ：
* 修改时间 : 年月日
* 修改内容 : 
****************************************************************************************************
*/
#pragma once

///IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
///						只包含本头文件需要用到的头文件
///#include "*.h"
///IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
#include "Includes.h"
 
///CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
///						宏(常量)定义区		CONSTANTS
///#define ...
///typedef enum {.,.,.}eXXX;
///CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
//=============UartDriver配置项===============需要修改配置的量
#ifndef USE_UART_NUM
#define USE_UART_NUM	(2)		//定义串口使用个数
#endif
//#define UART_USE_HAL_IDLE_INT		//定义是否使用HAL中的空闲中断驱动

//=============不用配置的宏(常量)定义===============

///PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
///						公有变量申明区     public VARIABLES
///extern ...;
///PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
#pragma pack()
///TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
///						类型类定义区		TYPES
///typedef ...;
///typedef struct {.;.;.;}sXXX;
///TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
#pragma pack(1)
#pragma pack()
#ifndef osFeature_Semaphore
typedef volatile int	Sem_Def;
#else
typedef osSemaphoreId	Sem_Def;
#endif

typedef struct
{
	UART_HandleTypeDef *phuart; /*指向UART句柄*/
	Sem_Def  TxCpltSem; /*发送完成信号量*/
	
	Sem_Def RxIdleSem; /*UART空闲中断信号量句柄或ID号*/
	unsigned char *pFrBuf; /*解码帧数据缓冲区，第2个缓冲区首址=BufSA+BufSize如果使用的话*/
	int FrLen; /*帧数据的长度*/
	unsigned short old_pos;
	int ReadTimeout;	//读取数据等待超时时间ms
	int IdleInterval;	//判断空闲时间间隔ms
//	unsigned int BufSize; /*接收缓冲区大小*/
//	int ReadErr; /*读取数据出错状态：0=UART_RX_NO_ERR帧结束,1=UART_RX_TIMEOUT,-1=串口发生硬件故障，2--接收完给定数(不使用DMA时)*/
}UartDriver;

///############################################################################
///						公有函数原型		public FUNCTION PROTOTYPES
///extern ...;		也可省略关键字extern
///#define	...		宏函数
///############################################################################
#pragma pack()
//描述 :启动发送数据
//返回 :0:成功，-1--访问UART故障，其它--见stm32fxxx_hal_uart.h中UART Error Code的定义
int UD_Transmit(
	UartDriver * obj/*[I]注册并初始化过的串口对象*/,
	unsigned char *pTxBuf/*[I]指向发送数据存放位置*/, 
	unsigned int size/*[I]传输字节数*/);

//描述: 注册串口对象
//返回: 0:成功；1:重复注册已经注册过了；-1:注册空间已经用完，需调整USE_UART_NUM数量。
int UD_Register(
	UartDriver **obj,/*[IO]指向驱动对象*/
	UART_HandleTypeDef *huart,/*[I]指向Uart句柄*/
	unsigned char *rxBuf,/*[I]接收缓冲区*/
	unsigned char *frBuf,/*[I]帧数据缓冲区*/
	unsigned int bufSize/*[I]缓冲区大小*/);

//描述: 对注册过的串口对象成员变量初始化
void UD_Init(
	UartDriver *obj,/*[I]注册过的串口对象*/
	Sem_Def	txSem,/*[I]发送信号量,等待Uart发送完成否?-1:不等, 其它:等*/
	Sem_Def	rxSem,/*[I]接收信号量*/
	int readTimeout,/*[I]读取数据超时时间ms*/
	int idleInterval/*[I]判断空闲时间间隔ms*/);

//描述: 接收由IdleInterval(空闲间隔时间)给定断帧的数据, 防止1帧中有2个以上的空闲位出现
//返回: 在FrBuf中帧数据长度
int UD_ReadFrameData(UartDriver *obj/*[I]注册并初始化过的串口对象*/);

//描述: 读取1帧数据发生超时回调函数
extern void UD_ReadTimeoutCallBack(UartDriver *obj /*[I]注册过的串口对象*/);
//描述: 通知调用者"我还活着"--运行正常
extern void UD_NoticeAliveCallBack(UartDriver *obj /*[I]注册过的串口对象*/);

//描述: 字节数组到16位整形数的转换(小端系统)
void UD_BytesToShort(void *sDat, const void *buf);
//描述: 从字节缓冲区中取出16位整形数(小端系统)
short UD_GetShort(const void *buf);
//描述: 16位整形数到字节数组的转换(小端系统)
void UD_ShortToBytes(void *buf, short sDat);

//描述: 字节数组到32位整形数的转换(小端系统)
void UD_BytesToInt(void *iDat, const void *buf);
//描述: 从字节缓冲区中取出32位整形数(小端系统)
int UD_GetInt(const void *buf);
//描述: 32位整形数到字节数组的转换(小端系统)
void UD_IntToBytes(const void *buf, int iDat);

//描述: 字节数组到32位浮点数的转换(小端系统)
void UD_BytesToFloat(void *fDat, const void *buf);
//描述: 从字节缓冲区中取出32位浮点数(小端系统)
float UD_GetFloat(const void *buf);
//描述: 32位浮点数到字节数组的转换(小端系统)
void UD_FloatToBytes(void *buf, float fDat);

//描述: 字节数组到64位浮点数的转换(小端系统)
void UD_BytesToDouble(void *dDat, const void *buf);
//描述: 从字节缓冲区中取出64位浮点数(小端系统)
double UD_GetDouble(const void  *buf);
//描述: 64位浮点数到字节数组的转换(小端系统)
void UD_DoubleToBytes(void *buf, double dDat);
